Client/server computing has become more and more important over the past few years in the information technology world. This type of distributed computing allows one machine to delegate some of its work to another machine that might be, for example, better suited to perform that work. For example, the server could be a high-powered computer running a database program managing the storage of a vast amount of data, while the client is simply a desktop personal computer (PC) which requests information from the database to use in one of its local programs.
The benefits of client/server computing have been even further enhanced by the use of a well-known computer programming technology called object-oriented programming (OOP), which allows the client and server to be located on different (heterogeneous) "platforms". In effect, objects are "distributed" throughout a network of computers of a plurality of platforms. A platform is a combination of the specific hardware/software/operating system/communication protocol which a machine uses to do its work. OOP allows the client application program and server application program to operate on their own platforms without worrying how the client application's work requests will be communicated and accepted by the server application. Likewise, the server application does not have to worry about how the OOP system will receive, translate and send the server application's processing results back to the requesting client application.
Details of how OOP techniques have been integrated with heterogeneous client/server systems are explained in U.S. Pat. No. 5,440,744 and European Patent Application 0 677,943 A2. These latter two publications are hereby incorporated by reference. However, an example, of the basic architecture will be given below for contextual understanding of the invention's environment.
As shown in FIG. 1, the client computer 10 (which could, for example, be a personal computer having the IBM OS/2 operating system installed thereon) has an application program 40 running on its operating system ("IBM" and "OS/2", are trademarks of the International Business Machines corporation). The application program 40 will periodically require work to be performed on the server computer 20 and/or data to be returned from the server 20 for subsequent use by the application program 40. The server computer 20 can be, for example, a high-powered mainframe computer running on IBM's MVS operating system ("MVS" is also a trademark of the IBM corp.). For the purposes of the present invention it is irrelevant whether the requests for communications services to be carried out by the server are instigated by user interaction with the first application program 40, or whether the application program 40 operates independently of user interaction and makes the requests automatically during the running of the program.
When the client computer 10 wishes to make a request for the server computer 20's services, the first application program 40 informs the first logic means 50 of the service required. It may for example do this by sending the first logic means the name of a remote procedure along with a list of input and output parameters. The first logic means 50 then handles the task of establishing the necessary communications with the second computer 20 with reference to definitions of the available communications services stored in the storage device 60. All the possible services are defined as a cohesive framework of object classes 70, these classes being derived from a single object class. Defining the services in this way gives rise to a great number of advantages in terms of performance and reusability.
To establish the necessary communication with the server 20, the first logic means 50 determines which object class in the framework needs to be used, and then creates an instance of that object at the server, a message being sent to that object so as to cause that object to invoke one of its methods. This gives rise to the establishment of the connection with the server computer 20 via the connection means 80, and the subsequent sending of a request to the second logic means 90.
The second logic means 90 then passes the request on to the second application program 100 (hereafter called either the service or server application) running on the server computer 20 so that the service application 100 can perform the specific task required by that request, such as running a data retrieval procedure. Once this task has been completed the service application may need to send results back to the first computer 10. The service application 100 interacts with the second logic means 90 during the performance of the requested tasks and when results are to be sent back to the first computer 10. The second logic means 90 establishes instances of objects, and invokes appropriate methods of those objects, as and when required by the service application 100, the object instances being created from the cohesive framework of object classes stored in the storage device 110.
Using the above technique, the client application program 40 is not exposed to the communications architecture. Further the service application 100 is invoked through the standard mechanism for its environment; it does not know that it is being invoked remotely.
The Object Management Group (OMG) is an international consortium of organizations involved in various aspects of client/server computing on heterogeneous platforms with distributed objects as is shown in FIG. 1. The OMG has set forth published standards by which client computers (e.g. 10) communicate (in OOP form) with server machines (e.g. 20). As part of these standards, an Object Request Broker (ORB) has been defined, which provides the object-oriented bridge between the client and the server machines. The ORB decouples the client and server applications from the object oriented implementation details, performing at least part of the work of the first and second logic means 50 and 90 as well as the connection means 80. The ORB also handles all interactions amongst various server objects of the service application 100.
Computer implemented transaction processing systems are used for critical business tasks in a number of industries. A transaction defines a single unit of work that must either be fully completed or fully purged without action. For example, in the case of a bank automated teller machine from which a customer seeks to withdraw money, the actions of issuing the money, reducing the balance of money on hand in the machine and reducing the customer's bank balance must all occur or none of them must occur. Failure of one of the subordinate actions would lead to inconsistency between the records and the actual occurrences.
Distributed transaction processing involves a transaction that affects resources at more than one physical or logical location. In the above example, a transaction affects resources managed at the local automated teller machine (ATM) as well as bank balances managed by a bank's main computer. Such transactions involve one particular client computer (e.g., 10) communicating with one particular server computer (e.g., 20) over a series of client requests which are processed by the server.
In typical client/server systems, client and server systems are each contributing to the overall processing of such transactions. Further, many different clients may be concurrently attempting to use the same server to engage in separate transactions. For example, many different banking ATM machines (client systems) may be trying to concurrently begin transactions so as to access data from a popular database program running on the bank's large central server. Further, there are even many different intra-server requests (i.e., requests passing from one server object to another server object) which may be part of separate (concurrent) transactions. In these situations, the server must be able to isolate these concurrent transactions so that they do not affect each other. That is, until one transaction is finished (either all parts are committed or all parts are aborted) other transactions trying to access the same server objects must be made to wait. The server objects which are involved in a transaction must be locked while the transaction is pending. Locking prevents extra-transactional concurrent accesses to the server objects which would effect the present transaction.
For example, if a husband is trying to transfer $2000 from a family's checking account into the family's higher interest paying savings account at an ATM machine at one bank on one side of town and his wife is attempting to perform the same function at another ATM (owned by a different bank) on the other side of town, the server must be able to deal with this situation effectively so that the two concurrent transactions do not create a problem for the bank owning the database server.
The way this problem has typically been solved in the object oriented programming context is for the server database program (server or service application program 100) to be written so as to not only perform the substantive functions of the program but also to perform transactional locking on concurrent accesses. That is, the server application 100 would be written so that it would lock access to the family's account data stored in the database once a first client (e.g. the husband's ATM) requests access. Then, the husband's transaction would continue in isolation despite the fact that the wife's transaction has been requested concurrently. The wife's client ATM would not be granted access to the data because the husband's client ATM would already have a lock on the object encapsulating this data.
The way such concurrency control is presently done is as follows. Each request from a client that arrives at a server must first pass through a concurrency control gateway that analyzes the request and compares it to the requests which have previously been granted access to the server resources and are still, in fact, accessing such resources. The purpose of this comparison is to determine whether the new request is compatible with the previous (and still current) requests. If so, the new request can be allowed to pass through the concurrency control gateway. If not, the new request should wait until at least one of the previous requests is finished.
Assume one client has issued a request to add money to the balance of a particular checking account (the checking account is represented in the server by a checking account object). Assume also that no other client requests have attempted to gain access to this particular checking account object. The server software has received this request and, upon analyzing it, determined from the operation involved (adding money to the balance) that this request needs to have "write access" to the checking account object (since the adding operation requires that the state of the checking account object be changed to increase the balance). Since no other request has tried to gain access to this object, there is no concurrency problem with respect to other requests, so the request is simply sent to the target object for execution of the request.
Now, while this request has access to the target object, assume another client is making a concurrent request to check the account balance of the same checking account object. The server software determines from the operation involved (checking bank balance) that this request requires "read access" to the target object. The server software then checks in a table to determine whether this new request can be given access to the target object concurrently with the other request which already has "write access". The table stores yes/no scalar values for each combination of a small number (usually about five) of access modes (read access, write access etc.).
In this example, the new request would be found from the table to conflict with the previous request, since the "read access" request must wait until the "write access" request has finished writing, otherwise the "read access" request would give a different result based on whether the "write access" request has actually changed the data or not when the "read access" request reads the data. To avoid this, the "read access" request is made to wait until the "write access" request is completely finished and is no longer accessing the target object (the "write access" request is said to have a "write lock" on the target object).
In the above discussion the requester of a lock on a server resource has been a transaction. That is, the locks are held by transactions. Concurrency control (access mode checking) is performed to determine whether two requests belonging to different transactions can be given concurrent access to the same server resource. Thus, as a first step, two requests are checked to determine if they belong to different transactions. If they do, a mode comparison is done to see if the access modes are compatible. Transaction identifiers are used to determine which request belongs to which transaction.
According to the OMG's Object Concurrency Control Service (OCCS) standard (See, e.g., CORBA Object Transaction Service Specification 1.0, OMG Document 94.8.4; and Concurrency Control Service Proposal, OMG TC Document 94.5.8), a dedicated interface for concurrency control with transactions as requesters is provided. Requests for access to server resources must be specifically written to this interface if the requester is a transaction. For example, the request is structured schematically as get.sub.-- transaction.sub.-- lock(my.sub.-- transaction, resource23). In this example, the request belongs to the transaction "my.sub.-- transaction" and is attempting to obtain a lock on the server resource "resource23".
The requester of a lock can also be a thread, such that the locks on the server resources are held by the thread of control from which the lock was requested rather than by the transaction to which the request belongs. As is well known, a thread is an operating system term referring to a portion of a process running on the processors of a particular machine at a particular time. In this case, concurrency control (access mode checking) is performed to determine whether two requests belonging to different threads can be given concurrent access to the same server resource. Thus, as a first step, two requests are checked to determine if they belong to different threads. If they do, a mode comparison is done to see if the access modes are compatible. Thread identifiers are used to determine which request belongs to which thread.
According to the OMG's OCCS standard, a dedicated interface for concurrency control with threads as requesters is provided. Requests for access to server resources must be specifically written to this interface if the requester is a thread. For example, the request is structured schematically as get.sub.-- thread.sub.-- lock(my.sub.-- thread, resource23). In this example, the request belongs to the thread "my.sub.-- thread" and is attempting to obtain a lock on the server resource "resource23".
Thus, requests must be structured in one form if the request is attempting to obtain a "transaction requester" lock and in another form if the request is attempting to obtain a "thread requester" lock. Thus, requests are limited to the concurrency control interface for which they were written. If a request is to go to a different interface, it must be rewritten into the other form. This limits the usefulness of a concurrency control service implementation. Further, there is a need to provide a separate interface for each requester type, which increases the total amount of software code.
Also, this prior concurrency control service implementation does not provide for other types of lock requesters to be defined in addition to transactions and threads. Thus, the computer programmer cannot modify the type or behavior of lock requester to suit a particular situation.